﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Security.Principal;
using FrameWork.Core.Cache;
using System.Data.Linq.Mapping;
using System.Configuration;
using System.Web;

namespace HYBY.Task.Repository.Dapper {
  /// <summary>
  /// 读取数据库连接---声明适用范围：这种方式的架构适用于一主多从或一主0从的 数据库架构
  /// </summary>
  public class DbConnectionHelper {
    private static readonly ConcurrentDictionary<string, string> ConnMapper = new ConcurrentDictionary<string, string>();//master
    private static readonly ConcurrentDictionary<string, string> ConnReadMapper = new ConcurrentDictionary<string, string>();//slaver

    internal static void Init() {
      ReadDbConnectionMapping();
    }

    internal static ConcurrentDictionary<string, string> Connections {
      get { return ConnMapper; }
    }

    /// <summary>
    /// 根据SQL 模板ID获取对应的数据库连接串
    /// </summary>
    /// <param name="statementId"></param>
    /// <returns></returns>
    public static string GetConnectionString(string statementId) {
      if (string.IsNullOrEmpty(statementId))
        return null;
      return ConnectionString(statementId, "read");
    }

    public static string GetProcdureConnStr(string statementId) {
      if (string.IsNullOrEmpty(statementId))
        return null;
      return ConnectionString(statementId, "write");
    }

    public static string GetConnectionString(Type type) {
      var attr = type.GetCustomAttributes(false).SingleOrDefault(x => x.GetType().Name == "DatabaseAttribute") as DatabaseAttribute;

      if (attr == null)
        throw new IdentityNotMappedException(string.Format("{0} Must Add DatabaseAttribute", type));

      if (string.IsNullOrWhiteSpace(attr.Name))
        throw new ArgumentNullException(type.Name);

      if (!ConnMapper.ContainsKey(attr.Name))
        throw new ArgumentNullException(string.Format("{0} Not in ConnMapper Dictionary", attr.Name));
      return ConnMapper[attr.Name];

    }

    public static string GetDatabaseName(Type type) {
      string name;
      var attr = type.GetCustomAttributes(false).SingleOrDefault(x => x.GetType().Name == "DatabaseAttribute") as DatabaseAttribute;

      if (attr == null)
        throw new IdentityNotMappedException("Not found DatabaseAttribute");

      if (string.IsNullOrWhiteSpace(attr.Name))
        throw new ArgumentNullException(type.Name);

      name = attr.Name;
      return name;
    }

    public static string GetDataTableName(Type type) {
      var attr = type.GetCustomAttributes(false).SingleOrDefault(x => x.GetType().Name == "TableAttribute") as TableAttribute;

      if (attr == null)
        throw new IdentityNotMappedException("Not found DatabaseAttribute");

      if (string.IsNullOrWhiteSpace(attr.Name))
        throw new ArgumentNullException(type.Name);

      string name = attr.Name;
      return name;
    }

    /// <summary>
    /// 读取数据库连接串
    /// </summary>
    private static void ReadDbConnectionMapping() {
      // 读取配置文件
      string FilePath = AppDomain.CurrentDomain.BaseDirectory + @"\Config\dbconnection.properties";            
      if (HttpContext.Current != null) {
        FilePath = HttpContext.Current.Server.MapPath("/Config") + @"\dbconnection.properties";        
      }     
      if (!File.Exists(FilePath))
        throw new Exception(string.Format("{0} not exist!", FilePath));

      var line = File.ReadAllLines(FilePath);
      foreach (var s in line) {
        if (string.IsNullOrWhiteSpace(s))
          continue;

        int index = s.IndexOf("=", StringComparison.Ordinal);
        if (index <= 0) {
          throw new ArgumentException(string.Format("Connection string  Error must have '='! [{0}]", s.Substring(index + 1)));
        }
        //TEST 读写分类
        //int connRw = s.Substring(0, index).IndexOf("_", StringComparison.OrdinalIgnoreCase);
        int connRw = s.Substring(0, index).IndexOf("#", StringComparison.OrdinalIgnoreCase);
        if (connRw > 0) //读库
                {
          ConnReadMapper.TryAdd(s.Substring(0, index), s.Substring(index + 1));
        }
        else {
          ConnMapper.TryAdd(s.Substring(0, index), s.Substring(index + 1));
        }
      }
    }

    private static string ConnectionString(string statementId, string flag) {
      //string cacheKey=string.Format("ConnCacheKey:{0}",statementId);
      //string rs = RedisCache.Instance.Get<string>(cacheKey);
      //if (!string.IsNullOrWhiteSpace(rs))
      //{
      //    return rs;
      //}
      //int index = statementId.IndexOf("_", StringComparison.Ordinal);
      int index = statementId.IndexOf("#", StringComparison.Ordinal);
      if (index <= 0)
        throw new ArgumentException(string.Format("{0} SQL ID Error! ", statementId));
      string key = statementId.Substring(0, index);
      if (flag == "write" || ConnReadMapper.Count <= 0)//明确主库或则没有读库 走主库链接
            {
        //RedisCache.Instance.Set<string>(cacheKey, ConnMapper[key],60);
        return ConnMapper[key];
      }
      int rnum = ConnReadMapper.Where(r => r.Key.Contains(key)).Count();
      if (rnum <= 0) //该库没有读库，则走主库
            {
        //RedisCache.Instance.Set<string>(cacheKey, ConnMapper[key], 60);
        return ConnMapper[key];
      }
      int m = Math.Abs(statementId.GetHashCode() % ConnReadMapper.Where(r => r.Key.Contains(key)).Count()) + 1;
      //string connkey = key + "_Read" + m;
      string connkey = key + "#Read" + m;
      if (ConnReadMapper.Keys.Contains(connkey)) {
        //RedisCache.Instance.Set<string>(cacheKey, ConnReadMapper[connkey], 60);
        return ConnReadMapper[connkey];
      }
      throw new ArgumentException(string.Format("只读库{0}配置错误", connkey));
    }
  }
}